using System;
using netDxf;

namespace TestDxfDocument
{
    public struct Matrix2
    {
        #region constructor
        public Matrix2(double m11, double m12, double m21, double m22)
        {
            this.m11 = m11;
            this.m12 = m12;
            this.m21 = m21;
            this.m22 = m22;
        }
        

        #endregion

        #region public properties

        public double M11
        {
            get => m11;
            set => m11 = value;
        }

        public double M12
        {
            get => m12;
            set => m12 = value;
        }

        public double M21
        {
            get => m21;
            set => m21 = value;
        }

        public double M22
        {
            get => m22;
            set => m22 = value;
        }

        #endregion

        #region private fields

        private double m11;
        private double m12;
        private double m21;
        private double m22;


        #endregion

        #region constants

        /// <summary>
        /// 
        /// </summary>
        public static Matrix2 Zero
        {
            get { return new Matrix2(0,0,0,0);}
        }

        /// <summary>
        /// 二阶单元矩阵
        /// </summary>
        public static Matrix2 Identity
        {
            get { return new Matrix2(1,0,0,1);}
        }


        #endregion

        #region overload operators

        public static Matrix2 operator +(Matrix2 a, Matrix2 b)
        {
            return new Matrix2(a.M11+b.M11,a.M12+b.M12,a.M21+b.M21,a.M22+b.M22);
        }
        
        public static Matrix2 Add(Matrix2 a, Matrix2 b)
        {
            return new Matrix2(a.M11+b.M11,a.M12+b.M12,a.M21+b.M21,a.M22+b.M22);
        }
        
        public static Matrix2 operator -(Matrix2 a, Matrix2 b)
        {
            return new Matrix2(a.M11-b.M11,a.M12-b.M12,a.M21-b.M21,a.M22-b.M22);
        }
        
        public static Matrix2 Subtract(Matrix2 a, Matrix2 b)
        {
            return new Matrix2(a.M11-b.M11,a.M12-b.M12,a.M21-b.M21,a.M22-b.M22);
        }

        public static Matrix2 operator *(Matrix2 a, Matrix2 b)
        {
            return new Matrix2(
                a.M11 * b.M11 + b.M21 * a.M12, b.M12 * a.M11 + b.M22 * a.M12,
                b.M11 * a.M21 + b.M21 * a.M22, b.M12 * a.M21 + b.M22 * a.M22);
        }
        
        public static Matrix2 Multiply(Matrix2 a, Matrix2 b)
        {
            return new Matrix2(
                a.M11 * b.M11 + b.M21 * a.M12, b.M12 * a.M11 + b.M22 * a.M12,
                b.M11 * a.M21 + b.M21 * a.M22, b.M12 * a.M21 + b.M22 * a.M22);
        }
        
        public static Vector2 operator *(Matrix2 a, Vector2 b)
        {
            return new Vector2(
                b.X * a.M11  + b.Y * a.M12,
                b.X * a.M21 + b.Y * a.M22);
        }
        
        public static Vector2 Multiply(Matrix2 a, Vector2 b)
        {
            return new Vector2(
                b.X * a.M11  + b.Y * a.M12,
                b.X * a.M21 + b.Y * a.M22);
        }
        
        public static Matrix2 operator *(Matrix2 a, double b)
        {
            return new Matrix2(
                b * a.M11 , b * a.M12,
                b * a.M21 , b * a.M22);
        }
        
        public static Matrix2 Multiply(Matrix2 a, double b)
        {
            return new Matrix2(
                b * a.M11 , b * a.M12,
                b * a.M21 , b * a.M22);
        }


        #endregion

        #region determinant

        public double Determinant()
        {
            return this.m11 * this.m22 - this.m12 * this.m21;
        }

        public Matrix2 Inverse()
        {
            var det = this.Determinant();
            if (MathHelper.IsZero(det))
            {
                throw new ArithmeticException("The matrix is not invertible.");
            }

            det = 1 / det;
            return new Matrix2(this.m22, -this.m12, -this.m21, this.m11) * det;
        }

        public Matrix2 Transpose()
        {
            return new Matrix2(this.m11, this.m21, this.m12, this.m22);
        }

        
        public static Matrix2 Rotation(double angleR)
        {
            var rotationMatrix = new Matrix2( Math.Cos(angleR), - Math.Sin(angleR),
                                              Math.Sin(angleR), Math.Cos(angleR));

            return rotationMatrix;
        }


        #endregion
    }
}